# -*- coding: utf8 -*-

from plugmgr import plugin
from twisted.python.log import msg
import sqlite3
import os

__all__ = ["config"]

class config(plugin):
    """конфиг представляет собой таблицу dictionary(jid, key, value)
    дополнительная таблица access(key, read_access, write_access)
    если jid == '', то этот параметр определён глобально, на все конфы
    если read_access/write_access - какой уровень доступа нужно иметь, чтобы смотреть/изменять опцию

    плагины должны юзать
        __getitem__(key): получить значение по ключу
        __setitem__(key, value): установить новое значение
        setdefault(key, value, read_access, write_access): установить значение и атрибуты,
            если такого ключа ещё нет в бд
        setattrs(key, read_access, write_access): установить атрибуты ключа
        getattrs(key): получить атрибуты ключа (tuple)
        keys(access): получить список ключей, где read_access <= access
        delete(key): удалить строку из бд по ключу (удаляется из access и dictionary)
        
        ATTENTION: __getitem__, __setitem__, setattrs предполагают что ключ уже есть в базе данных.
        Так что при инициализации плагина необходимо сделать setdefault() для всех ключей,
        которые он будет использовать

        в качестве ключа для __getitem__ и __setitem__ можно использовать строку-ключ (глобальный параметр),
        либо (jid, key) - параметр для jid
    """
    def __init__(self, bot):
        prefix = bot.config.var_dir
        if not os.access(prefix, os.W_OK): os.mkdir(prefix)
        # к конфигу доступ должен быть мгновенным, иначе фигня будет
        # поэтому асинхронное программирование тут не используем, но ставим таймаут 0
        self.db = sqlite3.connect(os.path.join(prefix, "config.db"), 0)
        self.cursor = self.db.cursor()
        self.cursor.execute("SELECT name FROM SQLITE_MASTER WHERE type='table' AND name='dictionary'")
        if not self.cursor.fetchall():
            # такой таблички в бд нет, надо создать
            # типы данных: http://www.sqlite.org/datatype3.html
            msg("Initializing config.db")
            self.cursor.execute("CREATE TABLE dictionary (jid text, key text, value text)")
            self.cursor.execute("CREATE UNIQUE INDEX jid_key ON dictionary(jid, key)")
            self.cursor.execute("CREATE TABLE access (key text, read_access integer, write_access integer)")
            self.cursor.execute("CREATE UNIQUE INDEX access_key ON access(key)")
    def _normalize(self, jid):
        return jid.split("/")[0].lower()
    def __getitem__(self, key):
        """если передан key - то возвращаем глобальное значение.
        если передан tuple(jid, key), то смотрим значение для jid, если не найдено, то глобальное"""
        if type(key) == tuple: jid, key = key
        else: jid = ''
        jid = self._normalize(jid)
        # desc - по убыванию длины jid, то есть сперва ищем по jid, если не найдено то по '' (глобальный конфиг)
        self.cursor.execute("SELECT value FROM dictionary WHERE key=? AND ((jid=?) OR (jid=?)) ORDER BY length(jid) DESC", (key, jid, ''))
        results = self.cursor.fetchall()
        if results: return results[0][0]
        else: raise KeyError("Key %s was not found in config table" % repr(key))
    def __setitem__(self, key, value):
        if type(key) == tuple: jid, key = key
        else: jid = ''
        jid = self._normalize(jid)
        self.cursor.execute("UPDATE dictionary set value=? where jid=? and key=?", (value, jid, key))
    def setattrs(self, key, read_access, write_access):
        self.cursor.execute("UPDATE access set read_access=?, write_access=? where key=?", (read_access, write_access, key))
    def getattrs(self, key):
        self.cursor.execute("SELECT read_access, write_access FROM access WHERE key=?", (key, ))
        results = self.cursor.fetchall()
        if results: return results[0]
        else: raise KeyError("Key %s was not found in access table" % repr(key))
    def setdefault(self, key, value, read_access, write_access):
        try: self.cursor.execute("INSERT INTO dictionary(jid, key, value) values(?, ?, ?)", ('', key, value))
        except sqlite3.IntegrityError: pass
        try: self.cursor.execute("INSERT INTO access(key, read_access, write_access) values(?, ?, ?)", \
            (key, read_access, write_access))
        except sqlite3.IntegrityError: pass
    def keys(self, access):
        self.cursor.execute("SELECT key FROM access WHERE read_access<=?", (access,))
        results = self.cursor.fetchall()
        return map(lambda x: x[0], results)
    def delete(self, key):
        self.cursor.execute("DELETE FROM access where key=?", (key, ))
        self.cursor.execute("DELETE FROM dictionary where key=?", (key, ))
    def unload(self):
        self.db.commit()
        self.db.close()
